package com.imgo.max.experience.service;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListenableFutureTask;
import com.imgo.max.artist.dto.DevoteInfo;
import com.imgo.max.cache.guava.ThreadPool;
import com.imgo.max.common.dto.APIException;
import com.imgo.max.common.dto.ResultCodeEnum;
import com.imgo.max.common.dto.ResultDO;
import com.imgo.max.common.log.CustomLogger;
import com.imgo.max.common.log.CustomLoggerFactory;
import com.imgo.max.common.result.ModuleResultCode;
import com.imgo.max.common.util.LoggerUtils;
import com.imgo.max.common.util.page.PageVO;
import com.imgo.max.common.util.page.Pagination;
import com.imgo.max.core.utils.JsonUntils;
import com.imgo.max.core.utils.StringUtil;
import com.imgo.max.diamond.dto.HistoryRecordDto;
import com.imgo.max.diamond.service.RechargeRecord2RedisService;
import com.imgo.max.experience.dao.PracticerExperienceMapper;
import com.imgo.max.experience.dao.PracticerExperienceMappingMapper;
import com.imgo.max.experience.dao.UserExperienceMapper;
import com.imgo.max.experience.dto.DreamFundConsumeDto;
import com.imgo.max.experience.dto.PracticerExperienceDto;
import com.imgo.max.experience.dto.UserExperienceDto;
import com.imgo.max.experience.mapping.*;
import com.imgo.max.image.service.PushService;
import com.imgo.max.ranklist.service.GeneralRankingService;
import com.imgo.max.user.dto.TaskBasicsDto;
import com.imgo.max.user.dto.UserTaskDto;
import com.imgo.max.user.service.UserTaskService;
import constant.ArtistConstant;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * 练习生的经验和梦想基金消息的消费类
 *
 * @Auth peter.Y
 * @Date 2016/07/27.
 */
@Component
public class PracticerExperienceHandler extends ExperienceHandlerParent {

    private static final CustomLogger logger = CustomLoggerFactory.getLogger(PracticerExperienceHandler.class);

    private List<PracticerExperienceMapping> exprMappingList = null;

    @Resource
    UserExperienceHandler userExperienceHandler;

    @Resource
    PracticerExperienceMapper experienceMapper;

    @Resource
    GeneralRankingService generalRankingService;

    @Resource
    UserTaskService userTaskService;

    @Resource
    PushService pushService;

    @Resource
    PracticerExperienceMappingMapper experienceMapping;

    @Resource
    RechargeRecord2RedisService rechargeRecord2RedisService;

    private String redis_fund_key = ArtistConstant.REDIS_ALL_PRACTICER_TOTAL_DREAM_FUND_KEY;

    @Override
    protected UserExperienceMapper getExprMapper() {
        return experienceMapper;
    }

    @Override
    protected String getRedisKey() {
        return ArtistConstant.REDIS_ALL_PRACTICER_TOTAL_EXPERIENCE_KEY;
    }

    @Override
    protected UserExperienceDto newDtoInstance() {
        return new PracticerExperienceDto();
    }

    @Override
    protected void initExprMappingList() {
        exprMappingList = experienceMapping.queryExperienceMapping();
    }

    public List<PracticerExperienceMapping> getExprMappingList() {
        return exprMappingList;
    }

    //用户等级的缓存
    LoadingCache<String, Integer> pracLevelLocalCache = CacheBuilder.newBuilder()
            // 设置并发级别为8，并发级别是指可以同时写缓存的线程数
            .concurrencyLevel(10)
            // 设置写缓存后8秒钟过期
            .expireAfterWrite(1, TimeUnit.DAYS)
            // 设置缓存多久失效,异步刷新
            .refreshAfterWrite(30, TimeUnit.SECONDS)
            // 设置缓存容器的初始容量为10
            .initialCapacity(1000)
            // 设置缓存最大容量为100，超过100之后就会按照LRU最近虽少使用算法来移除缓存项
            .maximumSize(10000)
            // 设置要统计缓存的命中率
            .recordStats()
            .build(new CacheLoader<String, Integer>() {

                /*
                 * (non-Javadoc)
                 * <p>Description: 加载:同步加载</p>
                 * @see com.google.common.cache.CacheLoader#load(java.lang.Object)
                 */
                @Override
                public Integer load(String key) throws InterruptedException, ExecutionException {
                    try {
                        return refreshLocalCache(key);
                    } catch (Exception e) {
                        logger.error("加载数据失败. req key:{}, error : {}", key, e);
                        throw e;
                    }
                }

                /*
                 * (non-Javadoc)
                 * <p>Description: 刷新:异步加载</p>
                 * @see com.google.common.cache.CacheLoader#reload(java.lang.Object, java.lang.Object)
                 */
                @Override
                public ListenableFuture<Integer> reload(final String key, Integer oldValue) throws InterruptedException,
                        ExecutionException {
                    ListenableFutureTask<Integer> task = ListenableFutureTask.create(new Callable<Integer>() {
                        public Integer call() throws InterruptedException, ExecutionException {
                            try {
                                return refreshLocalCache(key);
                            } catch (Exception e) {
                                logger.error("异步刷新数据失败. req key:{}, error : {}", key, e);
                                throw e;
                            }
                        }
                    });
                    ThreadPool.execute(task);
                    return task;
                }
            });

    private Integer refreshLocalCache(String key) {
        ResultDO<UserExperienceDto> resultDo = getUserExperience(key);
        if (resultDo.isSuccess()) {
            Integer level = 0;
            if (resultDo.getModule() != null) {
                level = resultDo.getModule().getLevel();
            }
            return level;
        }
        return null;
    }

    /**
     * 查询用户等级
     */
    @Override
    public ResultDO<Integer> getUserLevel(String uid) {
        ResultDO<Integer> resultDO = ResultDO.buildResult();
        try {
            int level = 0;
            //从本地缓存取
            Integer result = pracLevelLocalCache.get(uid);
            if (result != null) {
                level = result.intValue();
            }
            resultDO.setModule(level);
        } catch (ExecutionException e) {
            LoggerUtils.errorAndResultDO(logger, e, ModuleResultCode.EXPERIENCE, resultDO, uid);
        }
        return resultDO;
    }


    /**
     * 获取用户经验
     *
     * @param uid 用户ID
     * @return
     */
    @Override
    public ResultDO<UserExperienceDto> getUserExperience(String uid) {
        ResultDO<UserExperienceDto> resultDO = ResultDO.buildResult();
        try {
            resultDO = super.getUserExperience(uid);
            if (ResultDO.isSuccess(resultDO) && resultDO.getModule() != null) {
                PracticerExperienceDto dto = (PracticerExperienceDto) resultDO.getModule();
                Integer dreamFund = getDreamFund(uid);
                dto.setDreamFund(dreamFund);
            }
        } catch (Exception e) {
            LoggerUtils.errorAndResultDO(logger, e, ModuleResultCode.EXPERIENCE, resultDO, uid);
        }
        return resultDO;
    }

    /**
     * 获取用户经验
     *
     * @param uids 用户ID列表
     * @return
     */
    public ResultDO<List<UserExperienceDto>> getUsersExperience(List<String> uids) {
        ResultDO<List<UserExperienceDto>> resultDO = ResultDO.buildResult();
        try {
            resultDO = super.getUsersExperience(uids);
            if (ResultDO.isSuccess(resultDO) && resultDO.getModule() != null) {
                List<UserExperienceDto> dtos = resultDO.getModule();
                if (CollectionUtils.isNotEmpty(dtos)) {
                    Map<String, Integer> map = getDreamFunds(uids);
                    for (UserExperienceDto exprDto : dtos) {
                        PracticerExperienceDto praExpr = ((PracticerExperienceDto) exprDto);
                        praExpr.setDreamFund(map.get(exprDto.getUid()));
                    }
                }
            }
        } catch (Exception e) {
            LoggerUtils.errorAndResultDO(logger, e, ModuleResultCode.EXPERIENCE, resultDO, uids);
        }
        return resultDO;
    }

    /**
     * 获取艺人经验和等级
     *
     * @param beginLevel
     * @param endLevel
     * @param pagination
     * @return
     */
    public ResultDO<PageVO<PracticerExperienceDto>> getUsersExperienceByLevel(Integer beginLevel, Integer endLevel, Pagination pagination) {
        ResultDO<PageVO<PracticerExperienceDto>> resultDO = ResultDO.buildResult();
        try {
            if (beginLevel == null && endLevel == null) {
                throw new APIException(ResultCodeEnum.ARTIST_BEGIN_AND_END_PARAM_IS_NULL);
            }
            if (beginLevel != null && endLevel != null && endLevel < beginLevel) {
                throw new APIException(ResultCodeEnum.ARTIST_BEGIN_SMALL_END_PARAM);
            }
            if (pagination == null) {
                pagination = new Pagination();
            }
            Integer beginExpr = null;
            Integer endExpr = null;
            Integer maxExpr = null;
            int maxLevel = 1;
            for (PracticerExperienceMapping mapping : exprMappingList) {
                if (mapping.getLevel() == beginLevel) {
                    beginExpr = mapping.getStartScore();
                }
                if (mapping.getLevel() == endLevel) {
                    endExpr = mapping.getEndScore();
                }
                if (mapping.getLevel() > maxLevel) {
                    maxLevel = mapping.getLevel();
                    if (null == mapping.getEndScore()) {
                        maxExpr = mapping.getStartScore();
                    } else {
                        maxExpr = mapping.getEndScore();
                    }
                }
            }

            //如果输入级别大于最大级别，则结束经验为无穷大
            if (null == endLevel || endLevel > maxLevel) {
                endLevel = maxLevel;
                endExpr = null;
            }
            if (null == beginExpr) {
                beginExpr = maxExpr;
                endExpr = null;
            }
            int count = experienceMapper.queryExperienceCountByRange(beginExpr, endExpr);
            pagination.setTotal(count);
            List<PracticerExperience> experiences = experienceMapper.queryExperienceByRange(beginExpr, endExpr, pagination);

            PageVO<PracticerExperienceDto> pageVO = new PageVO<>();
            pageVO.setList(convertToExperienceDto(experiences));
            pageVO.setPagination(pagination);
            resultDO.setModule(pageVO);
        } catch (Exception e) {
            LoggerUtils.errorAndResultDO(logger, e, ModuleResultCode.EXPERIENCE, resultDO, beginLevel, endLevel, pagination);
        }
        return resultDO;
    }

    /**
     * 获取艺人经验和等级
     *
     * @param beginFund
     * @param endFund
     * @param pagination
     * @return
     */
    public ResultDO<PageVO<PracticerExperienceDto>> getUsersExperienceByDreamFund(Integer beginFund, Integer endFund, Pagination pagination) {
        ResultDO<PageVO<PracticerExperienceDto>> resultDO = ResultDO.buildResult();
        try {
            if (beginFund == null && endFund == null) {
                throw new APIException(ResultCodeEnum.ARTIST_BEGIN_AND_END_PARAM_IS_NULL);
            }
            if (pagination == null) {
                pagination = new Pagination();
            }
            int count = experienceMapper.queryExperienceCountByDreamFund(beginFund, endFund);
            pagination.setTotal(count);
            List<PracticerExperience> experiences = experienceMapper.queryExperienceByDreamFund(beginFund, endFund, pagination);
            PageVO<PracticerExperienceDto> pageVO = new PageVO<>();
            pageVO.setList(convertToExperienceDto(experiences));
            pageVO.setPagination(pagination);
            resultDO.setModule(pageVO);
        } catch (Exception e) {
            LoggerUtils.errorAndResultDO(logger, e, ModuleResultCode.EXPERIENCE, resultDO, beginFund, endFund, pagination);
        }
        return resultDO;
    }

    /**
     * 批量查询用户等级
     *
     * @param uids
     * @return
     */
    @Override
    public ResultDO<Map<String, Integer>> getUsersLevel(List<String> uids) {
        ResultDO<Map<String, Integer>> resultDO = ResultDO.buildResult();
        try {
            //从本地缓存取
            Map result = pracLevelLocalCache.getAll(uids);
            resultDO.setModule(result);
        } catch (ExecutionException e) {
            LoggerUtils.errorAndResultDO(logger, e, ModuleResultCode.EXPERIENCE, resultDO, uids);
        }
        return resultDO;
    }

    @Override
    protected Integer getLevel(Integer expr) {
        Integer result = 0;
        //要保证集合的顺序是从小到大
        for (PracticerExperienceMapping mapping : exprMappingList) {
            result = mapping.getLevel();
            if ((mapping.getEndScore() == null) || (mapping.getEndScore() >= expr)) {
                return result;
            }
        }
        return result;
    }

    /**
     * 处理送礼加经验
     *
     * @param devoteInfo
     */
    public void handleMessage(DevoteInfo devoteInfo) {
        String uid = devoteInfo.getArtistUid();
        if (StringUtils.isBlank(uid)) {
            logger.warn("累加经验的练习生ID为空,忽略累加");
            return;
        }

        boolean addSuccess = false;
        int absValue = Math.abs(devoteInfo.getDevoteValue());
        try {
            int result = 0;
            //只有减粉才能掉经验
            if ("0".equals(devoteInfo.getType())) {
                result = addDbExperience(uid, devoteInfo.getDevoteValue());
            } else {
                result = addDbExperience(uid, absValue);
            }

            if (result > 0) {
                addSuccess = true;
                freshExperience(uid);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            logger.error("add practicer experience failed, messageId: {}, content:{}", devoteInfo.getMessageId(), JsonUntils.toJson(devoteInfo));
        } finally {
            try {
                PracticerExperienceLog log = new PracticerExperienceLog();
                log.setUid(devoteInfo.getArtistUid());
                log.setGiftId(devoteInfo.getGid());
                log.setMessageId(devoteInfo.getMessageId());
                log.setSource(String.valueOf(devoteInfo.getType()));//贡献来源
                log.setValue("0".equals(devoteInfo.getType()) ? devoteInfo.getDevoteValue() : absValue);//只有减粉才能减经验
                log.setTime(devoteInfo.getTime());
                log.setFromUid(devoteInfo.getUid());
                log.setResult(addSuccess + "");
                experienceMapper.addExperienceLog(log);

            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                //如果消息中包含“MQ:”,则该日志会打印到failed_message.log日志中去
                logger.error("Practicer experience MQ:{}, content:{}", devoteInfo.getMessageId(), JsonUntils.toJson(devoteInfo));
            }
        }
    }

    public ResultDO<List<DreamFundConsumeDto>> queryDreamFundConsume(String uid, Pagination pagination) {
        if (StringUtils.isBlank(uid)) {
            logger.warn("查询梦想基金的练习生ID为空,忽略累加");
            return new ResultDO(ResultCodeEnum.USER_PARAMS_VALIDATE_UID_FAILURE, false);
        }
        if (pagination == null) {
            pagination = new Pagination();
        }

        ResultDO<List<HistoryRecordDto>> dtos = null;
        //TODO: 以后可能考虑加缓存

        try {
            List<DreamFundConsumeDto> records = new ArrayList<DreamFundConsumeDto>();
            if (dtos == null || CollectionUtils.isEmpty(dtos.getModule())) {
                List<DreamFundConsumeLog> logs = experienceMapper.queryDreamFundResumeLog(uid, pagination);

                if (!CollectionUtils.isEmpty(logs)) {
                    for (DreamFundConsumeLog log : logs) {
                        //只返回消费成功的记录
                        if ("true".equals(log.getResult())) {
                            DreamFundConsumeDto dto = new DreamFundConsumeDto();
                            dto.setAmount(log.getAmount());
                            dto.setPayTarget(log.getPayTarget());
                            dto.setTargetId(log.getTargetId());
                            dto.setOrderId(log.getOrderId());
                            dto.setConsumeTime(log.getConsumeTime());
                            records.add(dto);
                        }
                    }
                }
            } else {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                for (HistoryRecordDto dto : dtos.getModule()) {
                    DreamFundConsumeDto log = new DreamFundConsumeDto();
                    log.setAmount(Double.valueOf(dto.getPrice()).intValue());
                    log.setPayTarget("T");
                    log.setTargetId(dto.getProductId());
                    log.setOrderId(dto.getOrderId());
                    if (null != dto.getOccurTime()) {
                        log.setConsumeTime(sdf.parse(dto.getOccurTime()));
                    }
                    records.add(log);
                }
            }
            return new ResultDO(records);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            logger.error("调用失败experienceMapper.queryDreamFundResumeLog by uid {}", uid);
        }
        return new ResultDO(ResultCodeEnum.USER_UNKOWN_EXCEPTION, false);

    }

    /**
     * 消费梦想基金
     * 消费梦想基金会涨练习生的经验
     *
     * @param consumeDto
     * @return
     */
    public ResultDO<?> consumeDreamFund(DreamFundConsumeDto consumeDto) {
        boolean addSuccess = false;
        if (consumeDto.getConsumeTime() == null) {
            consumeDto.setConsumeTime(new Date());
        }
        if (consumeDto.getAmount() == null || consumeDto.getAmount() == 0) {
            return new ResultDO();
        }
        if (StringUtil.isEmpty(consumeDto.getPayTarget()) || StringUtil.isEmpty(consumeDto.getTargetId())) {
            return new ResultDO(ResultCodeEnum.DREAMFUND_TARGET_NOT_FULL, false);
        }

        int absAmount = Math.abs(consumeDto.getAmount());//必须保证是正数
        try {
            int result = 0;
            try {
                result = reduceDbDreamFund(consumeDto.getUid(), absAmount);

            } catch (Exception e) {
                addSuccess = false;
                logger.error(e.getMessage(), e);
                logger.error("consume practicer dreamfund failed, content: {}", JsonUntils.toJson(consumeDto));
            }
            if (result > 0) {
                try {
                    addSuccess = true;
                    freshDreamFund(consumeDto.getUid());
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                    logger.error("add practicer dreamfund cache failed, content: {}", JsonUntils.toJson(consumeDto));
                }
            } else {
                addSuccess = false;
                //余额不足
                return new ResultDO(ResultCodeEnum.DREAMFUND_NOT_ENOUGH, false);
            }
        } finally {
            try {
                DreamFundConsumeLog log = new DreamFundConsumeLog();
                log.setUid(consumeDto.getUid());
                log.setPayTarget(consumeDto.getPayTarget());//贡献来源
                log.setTargetId(consumeDto.getTargetId());
                log.setConsumeTime(consumeDto.getConsumeTime());
                log.setAmount(absAmount);
                log.setResult(addSuccess + "");
                log.setOrderId(consumeDto.getOrderId());
                experienceMapper.addDreamFundConsumeLog(log);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                //如果消息中包含“MQ:”,则该日志会打印到failed_message.log日志中去
                logger.error("Add dream fund consume log  failed, content:{}", JsonUntils.toJson(consumeDto));
            }
        }
        return new ResultDO();
    }


    /**
     * 处理送礼加梦想基金
     *
     * @param devoteInfo
     */
    public void handleFundMessage(DevoteInfo devoteInfo) {
        String aid = devoteInfo.getArtistUid();
        String uid = devoteInfo.getUid();
        if (StringUtils.isBlank(aid)) {
            logger.warn("累加梦想基金的练习生ID为空,忽略累加");
            return;
        }
        boolean addSuccess = false;
        logger.info("用户{}增加梦想基金{}", aid, devoteInfo.getTotalPrice());
        try {
            int result = addDbDreamFund(aid, devoteInfo.getTotalPrice());
            if (result > 0) {
                addSuccess = true;
                int myDreamFund = freshDreamFund(aid);

                //梦想基金增加以后，要同时给艺人和用户增加经验, 经验为基金的10倍,价格就是钻石数
                addDbExperience(aid, devoteInfo.getTotalPrice() * 10);
                userExperienceHandler.addDbExperience(uid, devoteInfo.getTotalPrice() * 10);

                userExperienceHandler.freshExperience(uid);
                freshExperience(aid);

                //开始自动支付众筹中基金数目已经满足的任务
                UserTaskDto userTaskDto = new UserTaskDto();
                userTaskDto.setUid(aid);//传艺人的id
                userTaskDto.setState("1");
                try {
                    ResultDO<UserTaskDto> resultDo = userTaskService.queryUserTaskModel(userTaskDto);
                    if (resultDo.isSuccess() && resultDo.getModule() != null) {
                        userTaskDto = resultDo.getModule();
                        String myTaskId = "" + userTaskDto.getId();
                        TaskBasicsDto taskBasicsDto = userTaskDto.getTaskBasicsDto();
                        int needFund = taskBasicsDto.getDreamfund();
                        //如果基金数目已经足够，则自动支付
                        if (myDreamFund >= needFund) {
                            DreamFundConsumeDto consumeDto = new DreamFundConsumeDto();
                            consumeDto.setUid(aid);//注意不要传成uid
                            consumeDto.setAmount(needFund);
                            consumeDto.setConsumeTime(new Date());
                            consumeDto.setPayTarget("T");
                            consumeDto.setTargetId(taskBasicsDto.getRid());
                            consumeDto.setOrderId(myTaskId);
                            logger.error("支付的任务ID 是{},userTaskId{}, myTaskId {}", taskBasicsDto.getRid(), taskBasicsDto.getUserTaskId(), myTaskId);
                            consumeDreamFund(consumeDto);

                            userTaskDto.setState("5"); //5表示已完成
                            userTaskService.updateUserTaskById(userTaskDto);

                            if (StringUtil.notEmpty(taskBasicsDto.getActivityId())) {
                                List uids = new ArrayList();
                                uids.add(aid);
                                try {
                                    //自动添加榜单
                                    generalRankingService.appendMembers(taskBasicsDto.getActivityId(), uids);
                                } catch (Exception e) {
                                    logger.error(e.getMessage(), e);
                                    logger.error("将用户添加到榜单{}失败，用户id为{}", taskBasicsDto.getActivityId(), aid);
                                }
                            }

                            try {
                                String content = "{\"u\":\"mglive://mglive/artistpace?uid=" + aid + "\",\"t\":\"芒果直播\",\"c\":\"你的众筹已完成，快去完成任务吧！\"}";
                                ResultDO<Boolean> pushResult = pushService.pushTransmissionMsgToSinge(aid, content);
                                if (!pushResult.isSuccess() || !pushResult.getModule()) {
                                    logger.error("推送众筹完成的消息失败，目标用户id为{}", aid);
                                }
                            } catch (Exception e) {
                                logger.error(e.getMessage(), e);
                                logger.error("推送众筹完成的消息失败，目标用户id为{}", aid);
                            }
                        }
                    }
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                    logger.error("pay task failed! aid: {}, taskId :{}, messageId :{}", aid, devoteInfo.getMessageId());
                }
            }


        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            logger.error("add dream fund failed, messageId: {}", devoteInfo.getMessageId());
        } finally {
            try {
                PracticerDreamFundLog log = new PracticerDreamFundLog();
                log.setUid(devoteInfo.getArtistUid());
                log.setGiftId(devoteInfo.getGid());
                log.setMessageId(devoteInfo.getMessageId());
                log.setSource(String.valueOf(devoteInfo.getType()));//贡献来源
                log.setValue(devoteInfo.getTotalPrice()); //梦想基金的数量
                log.setTime(devoteInfo.getTime());
                log.setFromUid(devoteInfo.getUid());
                log.setResult(addSuccess + "");
                experienceMapper.addDreamFundLog(log);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                //如果消息中包含“MQ:”,则该日志会打印到failed_message.log日志中去
                logger.error("Dream fund MQ:{}, content:{}", devoteInfo.getMessageId(), JsonUntils.toJson(devoteInfo));
            }
        }
    }

    /**
     * 刷新梦想基金的缓存
     *
     * @param uid
     * @return 梦想基金数
     */
    private int freshDreamFund(String uid) {
        PracticerExperience expr = (PracticerExperience) experienceMapper.queryExperienceByUid(uid);
        int fund = expr.getDreamFund();
        setRedisFund(uid, fund);
        return fund;
    }


    private int addDbDreamFund(String uid, Integer fund) {
        PracticerExperience praExpr = new PracticerExperience();
        praExpr.setUid(uid);
        praExpr.setDreamFund(fund);
        praExpr.setExperience(0);
        int result = experienceMapper.increaseDreamFund(praExpr);
        return result;
    }

    /**
     * 扣梦想基金
     *
     * @param uid
     * @param fund 扣除金额
     * @return
     */
    private int reduceDbDreamFund(String uid, Integer fund) {
        int result = experienceMapper.reduceDreamFund(uid, fund);
        return result;
    }

    /**
     * 获取练习生的梦想基金
     *
     * @param uid 用户ID
     * @return
     */
    private Integer getDreamFund(String uid) {

        Integer fund = getRedisDreamFund(uid);
        if (null == fund) {
            PracticerExperience exprDo = getPracticerDbData(uid);
            if (exprDo == null) {
                //添加一个空值到redis
                setRedisFund(uid, 0);
                return 0;
            }
            //添加到redis
            setRedisFund(uid, exprDo.getDreamFund());
            return exprDo.getDreamFund();
        }
        return fund;

    }

    /**
     * 批量获取练习生的梦想基金
     *
     * @param uids 用户ID列表
     * @return
     */
    private Map<String, Integer> getDreamFunds(List<String> uids) {
        Map<String, Integer> resultMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(uids) && uids.size() > 0) {
            List<String> funds = getRedisDreamFunds(uids);
            int i = 0;
            List<String> notFoundIdInRedis = new ArrayList<String>();
            for (String id : uids) {
                String redisFund = funds.get(i);
                i++;
                if (null == redisFund) {
                    notFoundIdInRedis.add(id);
                } else {
                    resultMap.put(id, Integer.valueOf(redisFund));
                }
            }

            if (notFoundIdInRedis.size() > 0) {
                List<UserExperience> exprDos = getDbDatas(notFoundIdInRedis);
                Map<String, String> fundsMap = new HashMap();
                Map<String, Integer> userExpMap = new HashMap<>();
                for (UserExperience userExp : exprDos) {
                    Integer fund = ((PracticerExperience) userExp).getDreamFund();
                    if (fund != null) {
                        userExpMap.put(userExp.getUid(), fund);
                    }
                }

                for (String uid : notFoundIdInRedis) {
                    Integer userFund = 0;
                    Integer tmpFundInt = userExpMap.get(uid);
                    if (tmpFundInt != null) {
                        userFund = tmpFundInt;
                    }
                    userExpMap.put(uid, userFund);
                    fundsMap.put(uid, userFund.toString());
                }

                //添加到redis
                setRedisFunds(fundsMap);
            }
        }
        return resultMap;
    }


    protected List<String> getRedisDreamFunds(List<String> uids) {
        List<String> funds = new ArrayList();
        try {
            funds = hashRedis.multiGet(redis_fund_key, uids);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return funds;
    }

    protected Integer getRedisDreamFund(String uid) {
        String fund = null;
        try {
            fund = hashRedis.get(redis_fund_key, uid);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return null == fund ? null : Integer.valueOf(fund);
    }


    protected PracticerExperience getPracticerDbData(String uid) {
        PracticerExperience expr = (PracticerExperience) experienceMapper.queryExperienceByUid(uid);
        return expr;
    }

    /**
     * 增加缓存中的梦想基金
     *
     * @param uid
     * @param fund
     */
    protected void setRedisFund(String uid, Integer fund) {
        try {
            if (fund != null) {
                hashRedis.put(redis_fund_key, uid, fund.toString());
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 增加缓存中的梦想基金
     *
     * @param fundMap
     */
    protected void setRedisFunds(Map<String, String> fundMap) {

        if (fundMap != null) {
            hashRedis.putAll(redis_fund_key, fundMap);
        }
    }

    private List<PracticerExperienceDto> convertToExperienceDto(List<PracticerExperience> exprs) {
        List<PracticerExperienceDto> dtos = new ArrayList();
        for (PracticerExperience expr : exprs) {
            PracticerExperienceDto dto = new PracticerExperienceDto();
            dto.setId(expr.getId().intValue());
            dto.setUid(expr.getUid());
            dto.setDreamFund(expr.getDreamFund());
            dto.setExperience(expr.getExperience());
            dto.setLevel(getLevel(expr.getExperience()));
            dtos.add(dto);
        }
        return dtos;
    }

    @Override
    protected String getRole() {
        // 练习生
        return "1";
    }


}
